﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;

namespace spike.reflection
{
    class Program
    {
        static void Main(string[] args)
        {
            var s = new Service();
            var c = new Client();
            //c.OnOutput += s.ProcessString;


            foreach (var ei in c.GetType().GetEvents())
            {
                Console.WriteLine("{0}, {1}", ei.Name, ei.EventHandlerType.Name);
                foreach (var pt in GetDelegateParameterTypes(ei.EventHandlerType))
                    Console.WriteLine("  {0}", pt.Name);
                Console.WriteLine(GetDelegateReturnType(ei.EventHandlerType).Name);

                if (ei.Name == "OnOutput")
                {
                    var mi = s.GetType().GetMethod("ProcessString");
                    Console.WriteLine(mi.Name);
                    ei.AddEventHandler(c, Delegate.CreateDelegate(ei.EventHandlerType, s, mi, false));
                    break;
                }
            }

            c.DoTheOutput("hello");
        }




        private static Type[] GetDelegateParameterTypes(Type d)
        {
            if (d.BaseType != typeof(MulticastDelegate))
                throw new ApplicationException("Not a delegate.");

            MethodInfo invoke = d.GetMethod("Invoke");
            if (invoke == null)
                throw new ApplicationException("Not a delegate.");

            ParameterInfo[] parameters = invoke.GetParameters();
            Type[] typeParameters = new Type[parameters.Length];
            for (int i = 0; i < parameters.Length; i++)
            {
                typeParameters[i] = parameters[i].ParameterType;
            }
            return typeParameters;
        }

        private static Type GetDelegateReturnType(Type d)
        {
            if (d.BaseType != typeof(MulticastDelegate))
                throw new ApplicationException("Not a delegate.");

            MethodInfo invoke = d.GetMethod("Invoke");
            if (invoke == null)
                throw new ApplicationException("Not a delegate.");

            return invoke.ReturnType;
        }
    }

    class Client
    {
        public event Action<string> OnOutput;

        public void DoTheOutput(string text)
        {
            this.OnOutput(text);
        }
    }

    class Service
    {
        public void ProcessString(string text)
        {
            Console.WriteLine(text);
        }
    }
}
